#pragma once
#include <winsock2.h>
#include <ws2tcpip.h>
#include <iostream>
#include <vector>
#include <unordered_map>

#pragma comment(lib, "Ws2_32.lib")

/**
 *                                  *******************
 *                                  * IO多路复用客户端类 *
 *                                  *******************
 *
 *使用示例：
 *
 * WSAPollServer server;
 * WSAPollClient client;
 *
 * 先启动服务器
 * std::thread serverThread([&server]() {
 *     server.start();
 * });
 *
 * 等待服务器启动
 * std::this_thread::sleep_for(std::chrono::seconds(2));
 * std::cout << "Server started!" << std::endl;
 *
 * 然后启动客户端
 * std::thread clientThread([&client]() {
 *     client.start();
 * });
 *
 * 等待客户端器启动
 * std::this_thread::sleep_for(std::chrono::seconds(2));
 *
 * 客户端发送消息给服务器
 * std::thread clientSendThread([&client]() {
 *      client.sendMessage("Hello from client");
 * );
 *
 * 等待线程结束
 * serverThread.join();
 * clientThread.join();
 * clientSendThread.join();
 *
 */
class WSAPollClient {

private:
    SOCKET m_socket = INVALID_SOCKET;
    std::vector<pollfd> m_pollfds;
    bool m_running = false;

private:

    /**
     *初始化WinSocket
     * @return
     */
    bool initializeWinSocket() {
        WSADATA wsaData;
        if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
            std::cout << "Client :WSAStartup failed: " << WSAGetLastError() << std::endl;
            return false;
        }
        return true;
    }

    /**
     *创建socket
     * @return
     */
    bool createSocket() {
        this->m_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
        if (this->m_socket == INVALID_SOCKET) {
            std::cout << "Socket creation failed: " << WSAGetLastError() << std::endl;
            return false;
        }
        return true;
    }

    /**
     * 链接服务器
     * @return
     */
    bool establishConnection() {
        sockaddr_in servAddr;
        servAddr.sin_family = AF_INET;
        servAddr.sin_port = htons(8081);
        inet_pton(AF_INET, "127.0.0.1", &servAddr.sin_addr);

        if (connect(this->m_socket, (sockaddr*)&servAddr, sizeof(servAddr)) == SOCKET_ERROR) {
            std::cout << "Client:Connection failed: " << WSAGetLastError() << std::endl;
            return false;
        }

        //加入pollfd
        this->m_pollfds.push_back({this->m_socket,POLLIN, 0});

        return true;
    }


    /**
     * 处理事件
     */
    void processEvents() {
        size_t i = 0;
        while (i < this->m_pollfds.size()) {

            //无事件不更新
            if (this->m_pollfds[i].revents == 0);

            else if (!this->handleServerData(i)) continue;

            i++;

        }
    }

    /**
     *
     * @param index
     * @return
     */
    bool handleServerData(size_t index) {

        char buffer[1024];
        int bytesReceived = recv(this->m_pollfds[index].fd, buffer, 1024, 0);

        //服务器关闭或者接受异常
        if (bytesReceived <= 0) {
            closesocket(this->m_pollfds[index].fd);
            this->m_pollfds.erase(m_pollfds.begin() + index);
            std::cout << "Client disconnected"<< std::endl;
            return false;
        }
        buffer[bytesReceived] = '\0';
        std::cout << "client_Received: " << buffer << std::endl;

        return true;
    }

    /**
    * 运行循环事件
    */
    void runEventLoop() {

        std::cout << "Client is running." << std::endl;
        while (this->m_running) {
            int ret = WSAPoll(this->m_pollfds.data(),(ULONG)this->m_pollfds.size(),1000);
            if (ret == SOCKET_ERROR) {
                std::cout << "Poll error: " << WSAGetLastError() << std::endl;
                break;
            }

            if (ret == 0) continue;//超时
            this->processEvents();
        }


    }

public:

    WSAPollClient() = default;

    ~WSAPollClient() {
        this->close();
    }


    /**
     * 启动客户端
     */
    void start() {
        if (!this->initializeWinSocket() || !this->createSocket() || !this->establishConnection()) return;


        this->m_running = true;
        this->runEventLoop();

    }


    /**
     *关闭客户端
     */
    void close() {

        //清除m_pollfds的数据
        std::vector<pollfd>::iterator it = this->m_pollfds.begin();
        while (it != this->m_pollfds.end()) {
            if (it->fd != INVALID_SOCKET) closesocket(it->fd);
            it++;
        }

        this->m_pollfds.clear();

        if (this->m_socket != INVALID_SOCKET) {
            closesocket(this->m_socket);
            this->m_socket = INVALID_SOCKET;
        }
        WSACleanup();
        this->m_running = false;
    }

    /**
     *发送消息到服务器
     * @param message
     * @return
     */
    bool sendMessage(const std::string& message) {

        if (!this->m_running) return false;

        if (send(this->m_socket, message.c_str(), (int)message.length(), 0) == SOCKET_ERROR) {
            std::cout << "Send failed: " << WSAGetLastError() <<std::endl;
            return false;
        }
        return true;
    }

};